package sk.fiit.lulco.grafy;

import java.util.Comparator;
import java.util.Random;

import sk.fiit.lulco.grafy.HEALConstants.SortType;

abstract class VertexComparator implements Comparator<Vertex> {
	private SortType type;
	
	public VertexComparator(SortType sort) {
		this.type = sort;
	}
	
	/**
	 * compare method
	 * 
	 * @param	Vertex	vertex1
	 * @param	Vertex	vertex2
	 * @return	integer
	 */
	public int compare(Vertex vertex1, Vertex vertex2) {
		switch (this.type) {
			case ASC: return compareVertexes(vertex1, vertex2);
			case DESC: return -compareVertexes(vertex1, vertex2);
		}
		return 0;
	}
	
	protected abstract int compareVertexes(Vertex vertex1, Vertex vertex2);
	
	public SortType getType() {
		return this.type;
	}
}

/**
 * class for vertex comparing by degree
 */
class VertexDegreeComparator extends VertexComparator {

	public VertexDegreeComparator(SortType sort) {
		super(sort);
	}

	/**
	 * compare method
	 * 
	 * @param	Vertex	vertex1
	 * @param	Vertex	vertex2
	 * @return	integer
	 */
	public int compareVertexes(Vertex vertex1, Vertex vertex2) {
		if (vertex1.getDegree() > vertex2.getDegree()) {
			return 1;
		} else if (vertex1.getDegree() < vertex2.getDegree()) {
			return -1;
		} else {
			return 0;
		}
	}
}

/**
 * class for vertex comparing by uncolored subgraph degree
 */
class VertexUncoloredSubgraphDegreeComparator extends VertexComparator {

	public VertexUncoloredSubgraphDegreeComparator(SortType sort) {
		super(sort);
	}

	/**
	 * compare method
	 * 
	 * @param	Vertex	vertex1
	 * @param	Vertex	vertex2
	 * @return	integer
	 */
	public int compareVertexes(Vertex vertex1, Vertex vertex2) {
		if (vertex1.getUncoloredSubgraphDegree() > vertex2.getUncoloredSubgraphDegree()) {
			return 1;
		} else if (vertex1.getUncoloredSubgraphDegree() < vertex2.getUncoloredSubgraphDegree()) {
			return -1;
		} else {
			return 0;
		}
	}
}

/**
 * class for vertex comparing by saturation degree
 */
class VertexSaturationDegreeComparator extends VertexComparator {

	public VertexSaturationDegreeComparator(SortType sort) {
		super(sort);
	}

	/**
	 * compare method
	 * 
	 * @param	Vertex	vertex1
	 * @param	Vertex	vertex2
	 * @return	integer
	 */
	public int compareVertexes(Vertex vertex1, Vertex vertex2) {
		if (vertex1.getSaturationDegree() > vertex2.getSaturationDegree()) {
			return 1;
		} else if (vertex1.getSaturationDegree() < vertex2.getSaturationDegree()) {
			return -1;
		} else {
			return 0;
		}
	}
}

/**
 * class for vertex comparing by random
 */
class VertexRandomComparator extends VertexComparator {

	public VertexRandomComparator(SortType sort) {
		super(sort);
	}
	
	/**
	 * compare method
	 * 
	 * @param	Vertex	vertex1
	 * @param	Vertex	vertex2
	 * @return	integer
	 */
	protected int compareVertexes(Vertex vertex1, Vertex vertex2) {
		Random randomGenerator = new Random();
		return randomGenerator.nextInt(3) - 1;
	}
}

/**
 * class for combined vertex comparing for Brelaz algorithm
 */
class VertexBrelazComparator extends VertexComparator {

	private static final VertexColorComparator cc = new VertexColorComparator(HEALConstants.SortType.DESC);
	private static final VertexSaturationDegreeComparator sdc = new VertexSaturationDegreeComparator(HEALConstants.SortType.ASC);
	private static final VertexUncoloredSubgraphDegreeComparator usdc = new VertexUncoloredSubgraphDegreeComparator(HEALConstants.SortType.ASC);
	private static final VertexRandomComparator rc = new VertexRandomComparator(HEALConstants.SortType.ASC);
	
	public VertexBrelazComparator(SortType sort) {
		super(sort);
	}

	/**
	 * compare method
	 * 
	 * @param	Vertex	vertex1
	 * @param	Vertex	vertex2
	 * @return	integer
	 */
	protected int compareVertexes(Vertex vertex1, Vertex vertex2) {
		int retVal;
		
		// because of this is the combination of more comparators, we have to
		// change sort type for those comparators which uses the same sort type as is defined
//		SortType type;
//		if (this.getType() == HEALConstants.SortType.ASC) {
//			type = HEALConstants.SortType.DESC;
//		} else {
//			type = HEALConstants.SortType.ASC;
//		}
		
		retVal = cc.compare(vertex1, vertex2);
		if (retVal == 0) {
			retVal = sdc.compare(vertex1, vertex2);
			if (retVal == 0) {
				retVal = usdc.compare(vertex1, vertex2);
				if (retVal == 0) {
					retVal = rc.compare(vertex1, vertex2);
				}
			}
		}
		return retVal;
	}
}

/**
 * class for vertex comparing by color
 */
class VertexColorComparator extends VertexComparator {

	public VertexColorComparator(SortType sort) {
		super(sort);
	}

	/**
	 * compare method
	 * 
	 * @param	Vertex	vertex1
	 * @param	Vertex	vertex2
	 * @return	integer
	 */
	protected int compareVertexes(Vertex vertex1, Vertex vertex2) {
		if (vertex1.getColor() > vertex2.getColor()) {
			return 1;
		} else if (vertex1.getColor() < vertex2.getColor()) {
			return -1;
		} else {
			return 0;
		}
	}
}

/**
 * class for vertex comparing by color
 */
class VertexConflictsComparator extends VertexComparator {

	public VertexConflictsComparator(SortType sort) {
		super(sort);
	}

	/**
	 * compare method
	 * 
	 * @param	Vertex	vertex1
	 * @param	Vertex	vertex2
	 * @return	integer
	 */
	protected int compareVertexes(Vertex vertex1, Vertex vertex2) {
		if (vertex1.getConflictsCount() > vertex2.getConflictsCount()) {
			return 1;
		} else if (vertex1.getConflictsCount() < vertex2.getConflictsCount()) {
			return -1;
		} else {
			return 0;
		}
	}
}

/**
 * class for vertex comparing for new algorithm
 */
class VertexNewAlgorithmComparator extends VertexComparator {

	public VertexNewAlgorithmComparator(SortType sort) {
		super(sort);
	}

	/**
	 * compare method
	 * 
	 * @param	Vertex	vertex1
	 * @param	Vertex	vertex2
	 * @return	integer
	 */
	protected int compareVertexes(Vertex vertex1, Vertex vertex2) {
		int retVal;
		VertexColorComparator cc = new VertexColorComparator(this.getType());
		retVal = cc.compare(vertex1, vertex2);
		if (retVal == 0) {
			VertexPageRankComparator prc = new VertexPageRankComparator(this.getType());
			retVal = prc.compare(vertex1, vertex2);
			if (retVal == 0) {
				VertexRandomComparator rc = new VertexRandomComparator(this.getType());
				retVal = rc.compare(vertex1, vertex2);
			}
		}
		return retVal;
	}
}

/**
 * class for vertex comparing by page rank
 */
class VertexPageRankComparator extends VertexComparator {

	public VertexPageRankComparator(SortType sort) {
		super(sort);
	}

	/**
	 * compare method
	 * 
	 * @param	Vertex	vertex1
	 * @param	Vertex	vertex2
	 * @return	integer
	 */
	protected int compareVertexes(Vertex vertex1, Vertex vertex2) {
//		if (vertex1.getPageRank() > vertex2.getPageRank()) {
//			return 1;
//		} else if (vertex1.getPageRank() < vertex2.getPageRank()) {
//			return -1;
//		} else {
			return 0;
//		}
	}
}